package com.platform.boot.security.filter;

import com.platform.boot.security.ReactiveSecurityHelper;
import com.platform.boot.security.SecurityUserDetails;
import org.springframework.core.Ordered;
import org.springframework.security.web.reactive.result.view.CsrfRequestDataValueProcessor;
import org.springframework.security.web.server.csrf.CsrfToken;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

/**
 * @author <a href="https://github.com/vnobo">Alex bob</a>
 */
public class AfterSecurityFilter implements WebFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {

        Mono<CsrfToken> csrfTokenMono = exchange.getAttribute(CsrfToken.class.getName());

        Mono<SecurityUserDetails> securityDetailsMono = exchange
                .getAttribute(ReactiveSecurityHelper.SECURITY_TOKEN_CONTEXT);

        if (csrfTokenMono != null) {
            if (securityDetailsMono != null) {
                return exchange.getSession()
                        .delayUntil(session -> csrfTokenMono.mapNotNull(csrfToken -> exchange.getAttributes()
                                .put(CsrfRequestDataValueProcessor.DEFAULT_CSRF_ATTR_NAME, csrfToken)))
                        .delayUntil(session -> securityDetailsMono.filter(s -> session.isStarted()
                                && !session.isExpired()).flatMap(securityDetails -> {
                            session.getAttributes()
                                    .put(ReactiveSecurityHelper.SECURITY_TOKEN_CONTEXT, securityDetails);
                            return session.save();
                        }))
                        .flatMap(session -> chain.filter(exchange));
            }
            return csrfTokenMono.flatMap(csrfToken -> chain.filter(exchange));
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }
}